package com.specificgroup.jira.plugin.acpro.util;

import com.specificgroup.jira.plugin.acpro.Constants;
import com.specificgroup.jira.plugin.acpro.exception.AcproXmlException;
import com.specificgroup.jira.plugin.acpro.exception.AcproException;
import com.specificgroup.jira.plugin.acpro.xml.response.generated.*;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.io.File;
import java.io.IOException;

/**
 *
 * @author Ivan Holub
 */
public class AcproUtil {

    private static final int SECONDS_IN_HOUR = 60 * 60;

    private static Logger log = Logger.getLogger(AcproUtil.class);

    public static List<String> tokenizeNotifyCC(String notifyCC) {
        StringTokenizer sttk = new StringTokenizer(notifyCC);
        List<String> retValue = new ArrayList<String>();
        while (sttk.hasMoreTokens()) {
            String token = sttk.nextToken();
            retValue.add(token);
        }
        return retValue;
    }

    public static Long parseAcproEstimate(String acproEstimateHours) throws AcproXmlException {
        try {
            Long hours = Long.valueOf(acproEstimateHours);
            Long retValue = SECONDS_IN_HOUR * hours;            
            return retValue;
        } catch (NumberFormatException e) {
            log.error("Error", e);
            throw new AcproXmlException("Acpro xml estimate is not valid number: " + acproEstimateHours, e);
        }
    }

    /**
     * Parses {@link DateEnteredType}.
     *
     * @param date the {@link DateEnteredType} object
     * @return date
     * @throws AcproXmlException in case of error
     */
    public static Date parseAcproDateEntered(DateEnteredType date) throws AcproXmlException {
        Date retValue = parseAcproDateTime(date.getYear(), date.getMonth(), date.getDay(), date.getHour(), date.getMinute(),
                date.getSecond());
        if (retValue == null) {
            throw new AcproXmlException("Acpro xml DateEnteredType is empty");
        }
        return retValue;
    }

    public static Date parseAcproDateLastChangedType(DateLastChangedType date) throws AcproXmlException {
        Date retValue = parseAcproDateTime(date.getYear(), date.getMonth(), date.getDay(), date.getHour(), date.getMinute(),
                date.getSecond());
        if (retValue == null) {
            throw new AcproXmlException("Acpro xml DateLastChangedType is empty");
        }
        return retValue;
    }

    public static Date parseAcproDateDeadline(DateDeadlineType date) throws AcproXmlException {
        Date retValue = parseAcproDateTime(date.getYear(), date.getMonth(), date.getDay(), date.getHour(), date.getMinute(),
                date.getSecond());
        return retValue;
    }

    public static Date parseAcproCommentDateTime(CommentDateTimeType date) throws AcproXmlException {
        Date retValue = parseAcproDateTime(date.getYear(), date.getMonth(), date.getDay(), date.getHour(), date.getMinute(),
                date.getSecond());
        if (retValue == null) {
            throw new AcproXmlException("Acpro xml CommentDateTimeType is empty");
        }
        return retValue;
    }

    public static Long parseAcproSizeBytes(String sizeBytes) throws AcproXmlException {
        try {
            Long retValue = Long.valueOf(sizeBytes);
            return retValue;
        } catch (NumberFormatException e) {
            log.error("Error", e);
            throw new AcproXmlException("Acpro xml sizeBytes is not valid number: " + sizeBytes, e);
        }
    }

    public static Date parseAcproDateTime(DateTimeType date) throws AcproXmlException {
        Date retValue = parseAcproDateTime(date.getYear(), date.getMonth(), date.getDay(), date.getHour(), date.getMinute(),
                date.getSecond());
        if (retValue == null) {
            throw new AcproXmlException("Acpro xml DateTimeType is empty");
        }
        return retValue;
    }

    private static Date parseAcproDateTime(String acproYear, String acproMonth, String acproDay, String acproHour,
                                           String acproMinute, String acproSecond) throws AcproXmlException {
        if (StringUtils.isEmpty(acproYear) &&
                StringUtils.isEmpty(acproMonth) &&
                StringUtils.isEmpty(acproDay) &&
                StringUtils.isEmpty(acproHour) &&
                StringUtils.isEmpty(acproMinute) &&
                StringUtils.isEmpty(acproSecond)) {
            return null;
        }
        //TODO timezone
        try {
            Calendar calendar = Calendar.getInstance();
            int year = Integer.valueOf(acproYear);
            calendar.set(Calendar.YEAR, year);
            int month = Integer.valueOf(acproMonth) - 1;
            calendar.set(Calendar.MONTH, month);
            int day = Integer.valueOf(acproDay);
            calendar.set(Calendar.DAY_OF_MONTH, day);
            int hour = Integer.valueOf(acproHour);
            calendar.set(Calendar.HOUR_OF_DAY, hour);
            int minute = Integer.valueOf(acproMinute);
            calendar.set(Calendar.MINUTE, minute);
            int second = 0;
            if (StringUtils.isNotEmpty(acproSecond)) {
                second = Integer.valueOf(acproSecond);
            }
            calendar.set(Calendar.SECOND, second);
            calendar.set(Calendar.MILLISECOND, 0);
            Date retValue = calendar.getTime();
            return retValue;
        } catch (NumberFormatException e) {
            log.error("Error", e);
            throw new AcproXmlException("Acpro xml datetime is not valid, " +
                "year: " + acproYear + ", " +
                "month: " + acproMonth + ", " +
                "day: " + acproDay + ", " +
                "hour: " + acproHour + ", " +
                "minute: " + acproMinute + ", " +
                "second: " + acproSecond, e);
        }
    }

    public static boolean isAcproUserKeyUnassigned(String userKey) {
        return Constants.ACPRO_UNASSIGNED_USER_KEY.equals(userKey);
    }

    public static boolean isAcproCategoryNotSet(String categoryKey) {
        return StringUtils.isEmpty(categoryKey);
    }

    public static boolean isAcproProductVersionSet(String productVersion) {
        return StringUtils.isNotEmpty(productVersion);
    }

    public static Map<String, UserType> buildUsersMap(GetUserListResponseType getUserListResponseType) {
        Map<String, UserType> retValue = new HashMap<String, UserType>();
        UsersType usersType = getUserListResponseType.getUsers();
        if (usersType != null) {
            for (UserType xmlUser: usersType.getUser()) {
                retValue.put(xmlUser.getUserKey(), xmlUser);
            }
        }
        return retValue;
    }

   public static void validateFileName(String fileName) throws AcproException {
       try {
           File file = File.createTempFile(fileName, fileName);
           file.delete();
       } catch (IOException e) {
           throw new AcproException("Acpro file name is not valid, file name: " + fileName);
       }
   }

}
